package ro.ubbcluj.cs.damate.plugin.monitors;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import ro.ubbcluj.cs.damate.plugin.events.ResourceEvent;
import ro.ubbcluj.cs.damate.plugin.services.DamateMonitoringService;
import static ro.ubbcluj.cs.damate.plugin.utils.PluginEventConstants.*;

/**
 * @author Lóránd Fazakas (lfazakas)
 *         Date: 2013.06.27.
 *         Time: 16:10
 */
public class ResourceMonitor implements EventMonitor  {

    private IResourceChangeListener resourceChangeListener;

    @Override
    public void startMonitoring(final DamateMonitoringService damateMonitoringService) {
        this.resourceChangeListener = new IResourceChangeListener() {
            @Override
            public void resourceChanged(IResourceChangeEvent event) {
                IResource res = event.getResource();
                ResourceEvent resourceEvent;
                try {
                    switch (event.getType()) {
                        case IResourceChangeEvent.PRE_CLOSE:
                            resourceEvent = new ResourceEvent(RESOURCE, CLOSED, true);
                            resourceEvent.addParameter(WORKSPACE, res.getWorkspace().getRoot().getLocation().toString());
                            resourceEvent.addParameter(PROJECT, res.getName());
                            resourceEvent.setResourceType(res.getType());
                            recordEvent(resourceEvent, damateMonitoringService);
                        break;
                        case IResourceChangeEvent.PRE_DELETE:
                            resourceEvent = new ResourceEvent(RESOURCE, DELETED, true);
                            resourceEvent.addParameter(WORKSPACE, res.getWorkspace().getRoot().getLocation().toString());
                            resourceEvent.addParameter(RESOURCE, res.getName());
                            resourceEvent.setResourceType(res.getType());
                            recordEvent(resourceEvent, damateMonitoringService);
                        break;
                        case IResourceChangeEvent.POST_CHANGE:
                            event.getDelta().accept(getDeltaVisitor(damateMonitoringService));
                        break;
                        case IResourceChangeEvent.POST_BUILD:
                            /*resourceEvent = new ResourceEvent(RESOURCE, BUILT);
                            resourceEvent.addParameter(WORKSPACE, res.getWorkspace().getRoot().getLocation().toString());
                            resourceEvent.addParameter(PROJECT, res.getProject().getName());
                            resourceEvent.addParameter(RESOURCE, res.getProjectRelativePath().toString());
                            resourceEvent.setResourceType(res.getType());
                            recordEvent(resourceEvent, damateMonitoringService);*/
                        break;
                     }
                } catch(CoreException e) {
                    e.printStackTrace();
                }
            }
        };

        ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener,
            IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE
            | IResourceChangeEvent.PRE_BUILD | IResourceChangeEvent.POST_BUILD
            | IResourceChangeEvent.POST_CHANGE);
    }

    private void recordEvent(ResourceEvent event, final DamateMonitoringService monitoringService) {
    		if (StringUtils.isEmpty(event.getParameters().get(RESOURCE))) {
    				event.setProject(true);
    		} else if (event.getParameters().get(RESOURCE).startsWith("bin")) {
    				return;
    		}
        monitoringService.recordEvent(event, null, null);
    }

    @Override
    public void stopMonitoring() {
        ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);
    }

    private IResourceDeltaVisitor getDeltaVisitor(final DamateMonitoringService damateMonitoringService) {
        return new IResourceDeltaVisitor() {
            public boolean visit(IResourceDelta delta) {
                IResource res = delta.getResource();
                ResourceEvent resourceEvent = new ResourceEvent(RESOURCE, CHANGED);
                resourceEvent.addParameter(WORKSPACE, res.getWorkspace().getRoot().getLocation().toString());                
                switch (delta.getKind()) {
                    case IResourceDelta.ADDED:
                        resourceEvent.setWhat(CREATED);
                        resourceEvent.addParameter(PROJECT, res.getProject().getName());
                        resourceEvent.addParameter(RESOURCE, res.getProjectRelativePath().toString());
                        resourceEvent.setResourceType(res.getType());
                        recordEvent(resourceEvent, damateMonitoringService);
                    break;
                    case IResourceDelta.REMOVED:
                        resourceEvent.setWhat(DELETED);
                        resourceEvent.addParameter(PROJECT, res.getProject().getName());
                        resourceEvent.addParameter(RESOURCE, res.getProjectRelativePath().toString());
                        resourceEvent.setResourceType(res.getType());
                        recordEvent(resourceEvent, damateMonitoringService);
                    break;
                    case IResourceDelta.CHANGED:
                        int flags = delta.getFlags();
                        if ((flags & IResourceDelta.CONTENT) != 0) {
                        		resourceEvent.addParameter(PROJECT, res.getProject().getName());
                        		resourceEvent.addParameter(RESOURCE, res.getProjectRelativePath().toString());
                                resourceEvent.setResourceType(res.getType());
                        		recordEvent(resourceEvent, damateMonitoringService);
                        }
                        if ((flags & IResourceDelta.REPLACED) != 0) {
                            //System.out.println("--> Content Replaced");
                        }
                        if ((flags & IResourceDelta.MARKERS) != 0) {
                            //System.out.println("--> Marker Change");
                            //IMarkerDelta[] markers = delta.getMarkerDeltas();
                            // if interested in markers, check these deltas
                        }
                    break;
                }
                return true; // visit the children
            }
        };
    }
}
